package exquery.util

import setupx.entity.*
import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter
import auth.util.UserUtil
import auth.entity.SecUser;

/**
 * User: pradeep
 * Date: Oct 15, 2010
 * Time: 2:35:16 PM
 * format web service to get experiment info.
 */
class WebServiceFormatUtil {

  Logger gLogger = Logger.getLogger(WebServiceFormatUtil.class)

  /**
   * to get Experiment info by experiment Id
   * @param experimentId
   * @return
   */
  Document getExperimentInfoByExperimentId(Long experimentId){

    Document doc = generateExperimentXML(experimentId)

    return doc
  }

  /**
   * to get Experiment info by experiment class Id
   * @param experimentClassId
   * @return
   */
  Document getExperimentInfoByExperimentClassId(Long experimentClassId){

    ExperimentClass ec = ExperimentClass.get(experimentClassId)

    Document doc = generateExperimentXML(ec?.experiment?.id);

    return doc
  }


  /**
   * to get Experiment info by class sample Id
   * @param classSampleId
   * @return
   */
  Document getExperimentInfoByClassSampleId(Long classSampleId){

    ClassSample cs = ClassSample.get(classSampleId)

    Document doc = generateExperimentXML(cs?.experimentclass?.experiment?.id)

    return doc
  }

    /**
     * generate Experiment XML
     * @param experimentId
     * @return
     */
    public Document generateExperimentXML(Long experimentId)
    {
        gLogger.info("=============== Coming into generateExperiment XML ================");
        gLogger.info("experimentId : "+experimentId);

        Document document = new Document();
        Element root = createElement("experiment");//experiment is the root of the XML

        if(experimentId!=null){

            Experiment experiment = Experiment.get(experimentId)
            gLogger.info("experiment : "+experiment);

            if(experiment!=null){
                if(experiment.id!=null){
                    root.setAttribute("id",experiment.id.toString());
                }else{
                    root.setAttribute("id","");
                }

                if(experiment.title!=null){
                    root.setAttribute("title",experiment.title.toString());
                }else{
                    root.setAttribute("title","");
                }

                Element publications = createPublicationsElement(experiment.experimentPublication);
                if(publications!=null){
                    root.addContent(publications);
                }

                Element classes = createClassesElement(experiment.experimentclassSet);
                if(classes!=null){
                    root.addContent(classes);
                }

                Element users = createUsersElement(experiment.experimentUserRights);
                if(users!=null){
                    root.addContent(users);
                }
            }

        }

        document.setContent(root);
        gLogger.info("=============== Out from create XML ================");
        gLogger.info("document : "+document);
        return document;
    }

    private Element createPublicationsElement(def publicationList){
        Element publications = createElement("publications");
        Element publication = null;

        if(publicationList!=null && publicationList instanceof Collection){

            publicationList.each {ExperimentPublication ep->
                if(ep!=null){
                    publication = setPublicationElement(ep);
                    if( publication!=null )
                    {
                        publications.addContent(publication);
                    }
                }
            }
        }

        return publications;
    }

    private Element setPublicationElement(ExperimentPublication ep){
        Element publication = createElement("publication");

        if(ep!=null){
            publication.setAttribute("id", ep.id.toString());
            publication.setAttribute("published_date", ep.publishedDate.toString());

            def displayName = UserUtil.getInstance().getUserDisplayNameByUserId(ep.publishedBy)

            if(displayName!=null && displayName.toString().trim().length()>0){
                publication.setAttribute("publishedby", UserUtil.getInstance().getUserDisplayNameByUserId(ep.publishedBy).toString());
            }else{
                publication.setAttribute("publishedby", "");
            }

            if(ep.label!=null && ep.label.toString().trim().length()>0){
                publication.setAttribute("comments", ep.label.toString());
            }else{
                publication.setAttribute("comments", "");
            }

        }
        return publication;
    }

    private Element createClassesElement(def experimentClassSet){
        Element classes = createElement("classes");
        Element clazz = null;

        if(experimentClassSet!=null){
            experimentClassSet.each {ExperimentClass ec->
                //gLogger.info("ec: "+ec);
                if(ec!=null){
                    clazz = setClassElement(ec);
                    if( clazz!=null )
                    {
                        classes.addContent(clazz);
                    }

                }
            }

        }

        return classes;
    }

    private Element setClassElement(ExperimentClass experimentClass){
        Element clazz = createElement("class")

        if(experimentClass!=null){

            if(experimentClass.id!=null){
                clazz.setAttribute("id", experimentClass.id.toString())
            }else{
                clazz.setAttribute("id", "")
            }

            String organStr = CommonUtil.getInstance().prepareOrgansText(experimentClass.organSet)
            String tissue = CommonUtil.getInstance().prepareOrgansTissueText(experimentClass.organSet)
            String cellType = CommonUtil.getInstance().prepareOrgansCellTypeText(experimentClass.organSet)
            String subCellularCellType = CommonUtil.getInstance().prepareOrgansSubcellularCelltype(experimentClass.organSet)

            if(organStr!=null && organStr.trim().length()>0){
                clazz.setAttribute("organ",organStr);
            }else{
                clazz.setAttribute("organ","");
            }

            if(tissue!=null && tissue.trim().length()>0){
                clazz.setAttribute("tissue",tissue);
            }else{
                clazz.setAttribute("tissue","");
            }

            if(cellType!=null && cellType.trim().length()>0){
                clazz.setAttribute("cellType",cellType);
            }else{
                clazz.setAttribute("cellType","");
            }

            if(subCellularCellType!=null && subCellularCellType.trim().length()>0){
                clazz.setAttribute("subCellularCellType",subCellularCellType);
            }else{
                clazz.setAttribute("subCellularCellType","");
            }

            String speciesStr = CommonUtil.getInstance().prepareSpeciesText(experimentClass.speciesSet)
            if(speciesStr!=null && speciesStr.trim().length()>0){
               clazz.setAttribute("species",speciesStr);
            }else{
               clazz.setAttribute("species","");
            }

            Element classMetaData = createMetaDatasElement(experimentClass.classMetadataSet);

            if(classMetaData!=null){
                Element metadata = null;

                if( experimentClass.genotype!=null && experimentClass.genotype.toString().trim().length()>0)
                {
                    metadata = createElement("metadata");
                    metadata.setAttribute("name", "Genotype");
                    metadata.setAttribute("value", experimentClass.genotype.toString());
                    classMetaData.addContent(metadata);
                }

                if( experimentClass.green_house!=null  && experimentClass.green_house.toString().trim().length()>0)
                {
                    metadata = createElement("metadata");
                    metadata.setAttribute("name", "Greenhouse");
                    metadata.setAttribute("value", experimentClass.green_house.toString());
                    classMetaData.addContent(metadata);
                }

                if( experimentClass.extraction!=null  && experimentClass.extraction.toString().trim().length()>0)
                {
                    metadata = createElement("metadata");
                    metadata.setAttribute("name", "Extraction");
                    metadata.setAttribute("value", experimentClass.extraction.toString());
                    classMetaData.addContent(metadata);
                }

                if( experimentClass.detailed_location!=null  && experimentClass.detailed_location.toString().trim().length()>0)
                {
                    metadata = createElement("metadata");
                    metadata.setAttribute("name", "Detailed Location");
                    metadata.setAttribute("value", experimentClass.detailed_location.toString());
                    classMetaData.addContent(metadata);
                }

                if( experimentClass.method_name!=null  && experimentClass.method_name.toString().trim().length()>0)
                {
                    metadata = createElement("metadata");
                    metadata.setAttribute("name", "Name");
                    metadata.setAttribute("value", experimentClass.method_name.toString());
                    classMetaData.addContent(metadata);
                }

                if( experimentClass.information!=null  && experimentClass.information.toString().trim().length()>0)
                {
                    metadata = createElement("metadata");
                    metadata.setAttribute("name", "Information");
                    metadata.setAttribute("value", experimentClass.information.toString());
                    classMetaData.addContent(metadata);
                }

                if( experimentClass.preparation!=null  && experimentClass.preparation.toString().trim().length()>0)
                {
                    metadata = createElement("metadata");
                    metadata.setAttribute("name", "Preparation");
                    metadata.setAttribute("value", experimentClass.preparation.toString());
                    classMetaData.addContent(metadata);
                }

                clazz.addContent(classMetaData);
            }

            Element samples = createSamplesElement(experimentClass.sampleSet);

            if(samples!=null){
                clazz.addContent(samples);
            }
        }

        return clazz;
    }

    private Element createSamplesElement(def sampleSet){
        Element samples = createElement("samples");
        Element sample = null;

        if(sampleSet!=null && sampleSet instanceof Collection){

              sampleSet.each {ClassSample cs->
                  //gLogger.info("cs: "+cs);
                  if(cs!=null){
                   sample = setSampleElement(cs);
                   if( sample!=null )
                   {
                       samples.addContent(sample);
                   }
              }
           }
        }
        return samples;
    }

    private Element setSampleElement(ClassSample cs){
        Element sample = createElement("sample");

        if(cs!=null){

            if(cs.id!=null){
                sample.setAttribute("id", cs.id.toString());
            }else{
                sample.setAttribute("id", "");
            }

            def chromatofStr = CommonUtil.getInstance().prepareChromatofsString(cs.sampleChromatofSet)
            if(chromatofStr!=null && chromatofStr.toString().trim().length() > 0){
                sample.setAttribute("fileName", chromatofStr);
            }else{
                sample.setAttribute("fileName", "");
            }


            if(cs.label!=null){
                sample.setAttribute("label", cs.label.toString());
            }else{
                sample.setAttribute("label", "");
            }

            if(cs.comments!=null){
                sample.setAttribute("comment",cs.comments.toString());
            }else{
                sample.setAttribute("comment","");
            }

            Element metadatas = createMetaDatasElement(cs.sampleMetadataSet);
            if(metadatas!=null){
                sample.addContent(metadatas);
            }
        }
        return sample;
    }

    private Element createMetaDatasElement(def metadataSet){
        Element metadatas = createElement("metadatas");
        Element metadata = null;

        if(metadataSet!=null && metadataSet instanceof Collection){
            metadataSet.each {md->
                if(md!=null){
                    metadata = setMetaDataElement(md);
                    if( metadata!=null )
                    {
                        metadatas.addContent(metadata);
                    }
                }
            }
        }
        return metadatas;
    }

    private Element setMetaDataElement(def md){
        Element metadata = null;

        if(md!=null){
            metadata = createElement("metadata");
            if(md.fieldTitle!=null){
                metadata.setAttribute("name", md.fieldTitle.toString());
            }else{
                metadata.setAttribute("name", "");
            }

            if(md.fieldValue!=null){
                metadata.setAttribute("value", md.fieldValue.toString());
            }else{
                metadata.setAttribute("value", "");
            }
        }
        return metadata;
    }

    private Element createUsersElement(def experimentUsers){
        Element users = createElement("users");
        Element user = null;

        if(experimentUsers!=null && experimentUsers instanceof Collection){
            experimentUsers.each {ExperimentUserRights eur->
                if(eur!=null && eur.secUser!=null){
                    user = setUserElement(eur.secUser);
                    if( user!=null )
                    {
                        users.addContent(user);
                    }
                }
            }
        }

        return users;
    }

    private Element setUserElement(SecUser secUser){
        Element user = null;

        if(secUser!=null){
            user = createElement("user");
            if(secUser.id!=null){
                user.setAttribute("id", secUser.id.toString());
            }else{
                user.setAttribute("id", "");
            }

//            if(secUser.username!=null){
//                user.setAttribute("name", secUser.username);
//            }else{
//                user.setAttribute("name", "");
//            }

            if(secUser.displayname!=null){
                user.setAttribute("displayname", secUser.displayname.toString());
            }else{
                user.setAttribute("displayname", "");
            }

//            if(secUser.password!=null){
//                user.setAttribute("password",secUser.password);
//            }else{
//                user.setAttribute("password","");
//            }

            if(secUser.email!=null){
                user.setAttribute("email", secUser.email.toString());
            }else{
                user.setAttribute("email", "");
            }
        }
        return user;
    }

    /*
      Create instance of XML Element
     * @param elementName
     * @return
     */
    public Element createElement(String elementName)
    {
        Element element = null;
        if( elementName!=null && elementName.trim().length()>0 )
        {
           element = new Element(elementName);
        }
        return element;
    }

    /**
     * save the XML and return path of the saved file
     * @param document
     * @param fileName
     * @param filePath
     * @return
     */
    public String saveXML(Document document, String fileName, String filePath){

        String savedFilePath = null;
        try
        {
            savedFilePath = filePath+"/"+fileName.toLowerCase()+".xml";

            XMLOutputter outputter = new XMLOutputter();

            // Set the XLMOutputter to pretty formatter. This formatter
            // use the TextMode.TRIM, which mean it will remove the
            // trailing white-spaces of both side (left and right)
            outputter.setFormat(Format.getPrettyFormat());

            // Write the document to a file and also display it on the screen through System.out.
            if(savedFilePath!=null || savedFilePath.trim().length()>0)
            {
              FileWriter writer = new FileWriter(savedFilePath);
              outputter.output(document, writer);
            }else{
              gLogger.error("Error! in XML Saving.");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
       return savedFilePath;
    }

    Random generator = new Random((new Date()).getTime());

    public String castXmlDocumentIntoString(Document document){
        String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><result>No Record Found</result>"
        try {
            if(document!=null){
                String randomFile = generator.nextLong().toString()
                File temp = File.createTempFile("temp${randomFile}",".xml")
                Writer fileWriter = new FileWriter(temp)
                XMLOutputter outPutter = new XMLOutputter();
                outPutter.output(document, fileWriter);
                result = temp.text
            }

        } catch (IOException ie) {
            ie.printStackTrace();
            result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><result>IO Exception in xml creation</result>"
            return result
        } catch (Exception e) {
            e.printStackTrace();
            result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><result>Exception in xml creation</result>"
            return result
        }
        return result
    }

}
